// 线程池
// 什么是线程池 ?? 一次创建一批线程 , 线程创建出来完成任务

// 实现什么样的线程池 ??  单例模式 -- 懒汉模式 , 用户直接使用线程池
//                      只能构造一次

#ifndef __THREAD__POOL__
#define __THREAD__POOL__
#include <iostream>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Log.hpp"

namespace ThreadPoolModel
{
    using namespace ThreadModel;
    using namespace MutexModel;
    using namespace CondModule;
    using namespace LogModel;

    const int default_thread_number = 5;

    template <typename T>
    class ThreadPool
    {
    private:
        void WakeUpAllThread()
        {
            LockGuard lockguard(_mutex);
            if (_sleepernum)
                _cond.Broadcast();
            LOG(LogLevel::INFO) << "唤醒所有的休眠线程";
        }

        void WakeUpOne()
        {
            LockGuard lockguard(_mutex);

            _cond.Signal();
            LOG(LogLevel::INFO) << "唤醒一个休眠线程";
        }

        // 实现单列模式
        ThreadPool()
        {
            // 直接插入 , 每个线程都执行任务处理函数
            for (int i = 0; i < _thread_number; ++i)
            {
                _threads_pool.emplace_back([this]()
                                           { Headler(); });
            }
        }

        // 启动
        void Run()
        {
            if (_isrunning)
                return;
            _isrunning = true;

            // 遍历 _threads_pool 正式创建线程
            for (auto &thread : _threads_pool)
            {
                // 这里正式创建线程
                thread.Start();
            }
        }

        // 只允许构造一次 , 拷贝 , 赋值均要禁止

        ThreadPool<T> &operator=(const ThreadPool<T> &self) = delete;
        ThreadPool(const ThreadPool<T> &) = delete;

    public:
        ~ThreadPool() {}

        static ThreadPool<T> *GetInstance()
        {
            // 这个是线程安全的 ,  如果已经创建了再次访问就直接返回 , 不在竞争锁了
            if (inc == nullptr)
            {
                // 加锁 , 多个线程都会访问单例
                {
                    LockGuard lockguard(_lock);
                    if (inc == nullptr)
                    {
                        LOG(LogLevel::INFO) << "首次使用单例 , 创建线程池";
                        inc = new ThreadPool<T>();
                        // 启动
                        inc->Run();
                    }
                }
            }

            return inc;
        }

        // 处理方法 -- 从队列中取任务 ,
        void Headler()
        {
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            while (true)
            {
                // 取任务然后处理任务
                T t;
                {
                    LockGuard lockguard(_mutex);
                    // 1. a.队列为空 b. 线程池没有退出
                    while (_task_queue.empty() && _isrunning)
                    {
                        _sleepernum++;
                        _cond.Wait(_mutex);
                        _sleepernum--;
                    }
                    // 2. 内部的线程被唤醒
                    if (!_isrunning && _task_queue.empty())
                    {
                        LOG(LogLevel::INFO) << name << " 退出了, 线程池退出&&任务队列为空";
                        break;
                    }

                    // 一定有任务
                    t = _task_queue.front(); // 从q中获取任务，任务已经是线程私有的了！！！
                    _task_queue.pop();
                }
                t(); // 正式处理任务 , 这里就会调用到 Route::RouteMessage 这个任务函数
                     // 处理完返回 , 到 servver.cc : 76 行处
            }
        }

        // 停止
        void Stop()
        {
            if (!_isrunning)
                return;
            _isrunning = false;

            // 停止了唤醒所有还在休眠的线程赶紧处理任务
            WakeUpAllThread();
        }

        // 等待线程
        void Join()
        {
            for (auto &thread : _threads_pool)
            {
                thread.Join();
            }
        }

        // 放任务 -- 入队列
        bool Equeue(T &in)
        {
            if (_isrunning)
            {
                LockGuard lockguard(_mutex);

                _task_queue.push(in);
                if (_threads_pool.size() == _sleepernum)
                    WakeUpOne();
                return true;
            }
            return false;
        }

    private:
        std::vector<Thread> _threads_pool;
        int _thread_number = default_thread_number; // 线程池中线程的个数

        // 任务队列 -- 扮演中间交易场所
        // 放不同类型的任务
        std::queue<T> _task_queue;

        bool _isrunning = false; // 是否运行
        int _sleepernum = 0;

        Mutex _mutex;
        Cond _cond;

        // 提供单例指针
        static ThreadPool<T> *inc;
        // 锁 , 多个线程会同时使用单例
        static Mutex _lock;
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::inc = nullptr;

    template <typename T>
    Mutex ThreadPool<T>::_lock;
}

#endif